home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume24 / cvs1.2upgrade / part02 < prev    next >
Encoding:
Internet Message Format  |  1991-03-05  |  51.0 KB

  1. Subject:  v24i015:  CVS upgrade for RCS5.5 support, Part02/02
  2. Newsgroups: comp.sources.unix
  3. Approved: rsalz@uunet.UU.NET
  4. X-Checksum-Snefru: b4a71b8b f1e6efa8 bb06cf4f 3dff118b
  5.  
  6. Submitted-by: Brian Berliner <berliner@central.sun.com>
  7. Posting-number: Volume 24, Issue 15
  8. Archive-name: cvs1.2upgrade/part02
  9.  
  10. #! /bin/sh
  11. # This is a shell archive.  Remove anything before this line, then feed it
  12. # into a shell via "sh file" or similar.  To overwrite existing files,
  13. # type "sh file -c".
  14. # The tool that generated this appeared in the comp.sources.unix newsgroup;
  15. # send mail to comp-sources-unix@uunet.uu.net if you want that tool.
  16. # Contents:  Patch02.02
  17. # Wrapped by rsalz@litchi.bbn.com on Mon Feb 25 16:05:39 1991
  18. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  19. echo If this archive is complete, you will see the following message:
  20. echo '          "shar: End of archive 2 (of 2)."'
  21. if test -f 'Patch02.02' -a "${1}" != "-c" ; then 
  22.   echo shar: Will not clobber existing file \"'Patch02.02'\"
  23. else
  24.   echo shar: Extracting \"'Patch02.02'\" \(48942 characters\)
  25.   sed "s/^X//" >'Patch02.02' <<'END_OF_FILE'
  26. X!  * Initial revision
  27. X!  * 
  28. X!  */
  29. X  
  30. X! /* minimal changes needed to get this file to work for CVS rather than RCS */
  31. X! /* #include "rcsbase.h" */
  32. X! #include <ctype.h>
  33. X! #include <time.h>
  34. X! #include "cvs.h"
  35. X! #define libId(x,y) static char x[] = y;
  36. X! #define P(x) ()
  37. X! #if !__STDC__
  38. X! #    define const
  39. X  #endif
  40. X+ /* see also `RCS' in comment below */
  41. X+ 
  42. X+ libId(partId, "$Id: partime.c,v 1.1.1.1 91/01/18 12:18:12 berliner Exp $")
  43. X  
  44. X+ #define given(v) (0 <= (v))
  45. X+ #define TMNULL (-1) /* Items not given are given this value */
  46. X+ #define TZ_OFFSET (24*60) /* TMNULL  <  zone_offset - TZ_OFFSET */
  47. X+ 
  48. X  struct tmwent {
  49. X!     const char *went;
  50. X!     short wval;
  51. X      char wflgs;
  52. X      char wtype;
  53. X  };
  54. X      /* wflgs */
  55. X  #define TWTIME 02    /* Word is a time value (absence implies date) */
  56. X  #define TWDST  04    /* Word is a DST-type timezone */
  57. X!     /* wtype */
  58. X! #define TM_MON    1    /* month name */
  59. X! #define TM_WDAY    2    /* weekday name */
  60. X! #define TM_ZON    3    /* time zone name */
  61. X! #define TM_LT    4    /* local time */
  62. X! #define TM_DST    5    /* daylight savings time */
  63. X! #define TM_12    6    /* AM, PM, NOON, or MIDNIGHT */
  64. X!     /* wval (for wtype==TM_12) */
  65. X! #define T12_AM 1
  66. X! #define T12_PM 2
  67. X! #define T12_NOON 12
  68. X! #define T12_MIDNIGHT 0
  69. X  
  70. X! static const struct tmwent tmwords [] = {
  71. X      {"january",      0, 0, TM_MON},
  72. X      {"february",     1, 0, TM_MON},
  73. X      {"march",        2, 0, TM_MON},
  74. X***************
  75. X*** 75,119 ****
  76. X      {"saturday",     6, 0, TM_WDAY},
  77. X  
  78. X      {"gmt",          0*60, TWTIME, TM_ZON},   /* Greenwich */
  79. X!     {"gst",          0*60, TWTIME, TM_ZON},
  80. X!     {"gdt",          0*60, TWTIME+TWDST, TM_ZON},     /* ?? */
  81. X  
  82. X      {"ast",          4*60, TWTIME, TM_ZON},   /* Atlantic */
  83. X      {"est",          5*60, TWTIME, TM_ZON},   /* Eastern */
  84. X      {"cst",          6*60, TWTIME, TM_ZON},   /* Central */
  85. X      {"mst",          7*60, TWTIME, TM_ZON},   /* Mountain */
  86. X      {"pst",          8*60, TWTIME, TM_ZON},   /* Pacific */
  87. X!     {"yst",          9*60, TWTIME, TM_ZON},   /* Yukon */
  88. X      {"hst",          10*60, TWTIME, TM_ZON},  /* Hawaii */
  89. X!     {"bst",          11*60, TWTIME, TM_ZON},  /* Bering */
  90. X  
  91. X      {"adt",          4*60, TWTIME+TWDST, TM_ZON},     /* Atlantic */
  92. X      {"edt",          5*60, TWTIME+TWDST, TM_ZON},     /* Eastern */
  93. X      {"cdt",          6*60, TWTIME+TWDST, TM_ZON},     /* Central */
  94. X      {"mdt",          7*60, TWTIME+TWDST, TM_ZON},     /* Mountain */
  95. X      {"pdt",          8*60, TWTIME+TWDST, TM_ZON},     /* Pacific */
  96. X!     {"ydt",          9*60, TWTIME+TWDST, TM_ZON},     /* Yukon */
  97. X!     {"hdt",          10*60, TWTIME+TWDST, TM_ZON},    /* Hawaii */
  98. X!     {"bdt",          11*60, TWTIME+TWDST, TM_ZON},    /* Bering */
  99. X! 
  100. X!     {"daylight",     1, TWTIME+TWDST, TM_ZON},        /* Local Daylight */
  101. X!     {"standard",     1, TWTIME, TM_ZON},      /* Local Standard */
  102. X!     {"std",          1, TWTIME, TM_ZON},      /*   "       "    */
  103. X! 
  104. X!     {"am",           1, TWTIME, TM_AMPM},
  105. X!     {"pm",           2, TWTIME, TM_AMPM},
  106. X!     {"noon",         12,TWTIME+TW1200, 0},    /* Special frobs */
  107. X!     {"midnight",     0, TWTIME+TW1200, 0},
  108. X!     {"at",           (long)ptnoise, TWSPEC, 0},    /* Noise word */
  109. X  
  110. X      {0, 0, 0, 0},             /* Zero entry to terminate searches */
  111. X  };
  112. X  
  113. X- #define TMWILD (-2)    /* Value meaning item specified as wild-card */
  114. X-             /* (May use someday...) */
  115. X- 
  116. X  struct token {
  117. X!     char *tcp;    /* pointer to string */
  118. X      int tcnt;    /* # chars */
  119. X      char tbrk;    /* "break" char */
  120. X      char tbrkl;    /* last break char */
  121. X--- 123,230 ----
  122. X      {"saturday",     6, 0, TM_WDAY},
  123. X  
  124. X      {"gmt",          0*60, TWTIME, TM_ZON},   /* Greenwich */
  125. X!     {"utc",          0*60, TWTIME, TM_ZON},
  126. X!     {"ut",           0*60, TWTIME, TM_ZON},
  127. X  
  128. X+     {"nzst",        -12*60, TWTIME, TM_ZON},  /* New Zealand */
  129. X+     {"jst",         -9*60, TWTIME, TM_ZON},   /* Japan */
  130. X+     {"kst",         -9*60, TWTIME, TM_ZON},   /* Korea */
  131. X+     {"ist",         -5*60-30, TWTIME, TM_ZON},/* India */
  132. X+     {"eet",         -2*60, TWTIME, TM_ZON},   /* Eastern Europe */
  133. X+     {"cet",         -1*60, TWTIME, TM_ZON},   /* Central Europe */
  134. X+     {"met",         -1*60, TWTIME, TM_ZON},   /* Middle Europe */
  135. X+     {"wet",          0*60, TWTIME, TM_ZON},   /* Western Europe */
  136. X+     {"nst",          3*60+30, TWTIME, TM_ZON},/* Newfoundland */
  137. X      {"ast",          4*60, TWTIME, TM_ZON},   /* Atlantic */
  138. X      {"est",          5*60, TWTIME, TM_ZON},   /* Eastern */
  139. X      {"cst",          6*60, TWTIME, TM_ZON},   /* Central */
  140. X      {"mst",          7*60, TWTIME, TM_ZON},   /* Mountain */
  141. X      {"pst",          8*60, TWTIME, TM_ZON},   /* Pacific */
  142. X!     {"akst",         9*60, TWTIME, TM_ZON},   /* Alaska */
  143. X!     {"hast",         10*60, TWTIME, TM_ZON},  /* Hawaii-Aleutian */
  144. X      {"hst",          10*60, TWTIME, TM_ZON},  /* Hawaii */
  145. X!     {"sst",          11*60, TWTIME, TM_ZON},  /* Samoa */
  146. X  
  147. X+     {"nzdt",        -12*60, TWTIME+TWDST, TM_ZON},    /* New Zealand */
  148. X+     {"kdt",         -9*60, TWTIME+TWDST, TM_ZON},     /* Korea */
  149. X+     {"bst",          0*60, TWTIME+TWDST, TM_ZON},     /* Britain */
  150. X+     {"ndt",          2*60+30, TWTIME+TWDST, TM_ZON}, /*Newfoundland (DDST)*/
  151. X      {"adt",          4*60, TWTIME+TWDST, TM_ZON},     /* Atlantic */
  152. X      {"edt",          5*60, TWTIME+TWDST, TM_ZON},     /* Eastern */
  153. X      {"cdt",          6*60, TWTIME+TWDST, TM_ZON},     /* Central */
  154. X      {"mdt",          7*60, TWTIME+TWDST, TM_ZON},     /* Mountain */
  155. X      {"pdt",          8*60, TWTIME+TWDST, TM_ZON},     /* Pacific */
  156. X!     {"akdt",         9*60, TWTIME+TWDST, TM_ZON},     /* Alaska */
  157. X!     {"hadt",         10*60, TWTIME+TWDST, TM_ZON},    /* Hawaii-Aleutian */
  158. X! 
  159. X! #if 0
  160. X!     /*
  161. X!      * The following names are duplicates or are not well attested.
  162. X!      * A standard is needed.
  163. X!      */
  164. X!     {"?st",         -13*60, TWTIME, TM_ZON},  /* Uelen */
  165. X!     {"?st",         -11*60, TWTIME, TM_ZON},  /* Magadan */
  166. X!     {"east",        -10*60, TWTIME, TM_ZON},  /* Eastern Australia */
  167. X!     {"cast",        -9*60-30, TWTIME, TM_ZON},/* Central Australia */
  168. X!     {"cst",         -8*60, TWTIME, TM_ZON},   /* China */
  169. X!     {"hkt",         -8*60, TWTIME, TM_ZON},   /* Hong Kong */
  170. X!     {"sst",         -8*60, TWTIME, TM_ZON},   /* Singapore */
  171. X!     {"wast",        -8*60, TWTIME, TM_ZON},   /* Western Australia */
  172. X!     {"?st",         -7*60, TWTIME, TM_ZON},   /* Novosibirsk */
  173. X!     {"jt",          -7*60-30, TWTIME, TM_ZON},/* Java */
  174. X!     {"nst",         -6*60-30, TWTIME, TM_ZON},/* North Sumatra */
  175. X!     {"?st",         -6*60, TWTIME, TM_ZON},   /* Tashkent */
  176. X!     {"?st",         -5*60, TWTIME, TM_ZON},      /* Sverdlovsk */
  177. X!     {"?",           -4*60-30, TWTIME, TM_ZON},/* Afghanistan */
  178. X!     {"?st",         -4*60, TWTIME, TM_ZON},      /* Rostov */
  179. X!     {"it",          -3*60-30, TWTIME, TM_ZON},/* Iran */
  180. X!     {"?st",         -3*60, TWTIME, TM_ZON},   /* Moscow */
  181. X!     {"ist",         -2*60, TWTIME, TM_ZON},   /* Israel */
  182. X!     {"ast",          1*60, TWTIME, TM_ZON},   /* Azores */
  183. X!     {"fst",          2*60, TWTIME, TM_ZON},   /* Fernando de Noronha */
  184. X!     {"bst",          3*60, TWTIME, TM_ZON},   /* Brazil */
  185. X!     {"wst",          4*60, TWTIME, TM_ZON},   /* Western Brazil */
  186. X!     {"ast",          5*60, TWTIME, TM_ZON},   /* Acre Brazil */
  187. X!     {"?",            9*60+30, TWTIME, TM_ZON},/* Marquesas */
  188. X!     {"?st",          12*60, TWTIME, TM_ZON},  /* Kwajalein */
  189. X! 
  190. X!     {"?dt",         -13*60, TWTIME+TWDST, TM_ZON},      /* Uelen */
  191. X!     {"?dt",         -11*60, TWTIME+TWDST, TM_ZON},      /* Magadan */
  192. X!     {"eadt",        -10*60, TWTIME+TWDST, TM_ZON},    /* Eastern Australia */
  193. X!     {"cadt",        -9*60-30, TWTIME+TWDST, TM_ZON},  /* Central Australia */
  194. X!     {"cdt",         -8*60, TWTIME+TWDST, TM_ZON},     /* China */
  195. X!     {"wadt",        -8*60, TWTIME+TWDST, TM_ZON},     /* Western Australia */
  196. X!     {"?dt",         -7*60, TWTIME+TWDST, TM_ZON},      /* Novosibirsk */
  197. X!     {"?dt",         -6*60, TWTIME+TWDST, TM_ZON},      /* Tashkent */
  198. X!     {"?dt",         -5*60, TWTIME+TWDST, TM_ZON},      /* Sverdlovsk */
  199. X!     {"?dt",         -4*60, TWTIME+TWDST, TM_ZON},      /* Rostov */
  200. X!     {"?dt",         -3*60, TWTIME+TWDST, TM_ZON},     /* Moscow */
  201. X!     {"idt",         -2*60, TWTIME+TWDST, TM_ZON},     /* Israel */
  202. X!     {"eest",        -2*60, TWTIME+TWDST, TM_ZON},     /* Eastern Europe */
  203. X!     {"cest",        -1*60, TWTIME+TWDST, TM_ZON},     /* Central Europe */
  204. X!     {"mest",        -1*60, TWTIME+TWDST, TM_ZON},     /* Middle Europe */
  205. X!     {"west",         0*60, TWTIME+TWDST, TM_ZON},     /* Western Europe */
  206. X!     {"adt",          1*60, TWTIME+TWDST, TM_ZON},      /* Azores */
  207. X!     {"fdt",          2*60, TWTIME+TWDST, TM_ZON},     /* Fernando de Noronha */
  208. X!     {"edt",          3*60, TWTIME+TWDST, TM_ZON},     /* Eastern Brazil */
  209. X!     {"wdt",          4*60, TWTIME+TWDST, TM_ZON},     /* Western Brazil */
  210. X!     {"adt",          5*60, TWTIME+TWDST, TM_ZON},     /* Acre Brazil */
  211. X! #endif
  212. X! 
  213. X!     {"lt",           0, TWTIME, TM_LT},       /* local time */
  214. X!     {"dst",          1*60, TWTIME, TM_DST},      /* daylight savings time */
  215. X!     {"ddst",         2*60, TWTIME, TM_DST},      /* double dst */
  216. X! 
  217. X!     {"am",           T12_AM,    TWTIME, TM_12},
  218. X!     {"pm",           T12_PM,    TWTIME, TM_12},
  219. X!     {"noon",         T12_NOON,    TWTIME, TM_12},
  220. X!     {"midnight",     T12_MIDNIGHT,    TWTIME, TM_12},
  221. X  
  222. X      {0, 0, 0, 0},             /* Zero entry to terminate searches */
  223. X  };
  224. X  
  225. X  struct token {
  226. X!     const char *tcp;/* pointer to string */
  227. X      int tcnt;    /* # chars */
  228. X      char tbrk;    /* "break" char */
  229. X      char tbrkl;    /* last break char */
  230. X***************
  231. X*** 120,227 ****
  232. X      char tflg;    /* 0 = alpha, 1 = numeric */
  233. X      union {         /* Resulting value; */
  234. X          int tnum;/* either a #, or */
  235. X!         struct tmwent *ttmw;/* ptr to a tmwent. */
  236. X      } tval;
  237. X  };
  238. X  
  239. X! partime(astr, atm)
  240. X! char *astr;
  241. X! struct tm *atm;
  242. X! {    register int *tp;
  243. X!     register struct tmwent *twp;
  244. X!     register int i;
  245. X!     struct token btoken, atoken;
  246. X!     char *cp, ch;
  247. X!     int ord, midnoon;
  248. X!     int (*aproc)();
  249. X! 
  250. X!     tp = (int *)atm;
  251. X!     zaptime(tp);             /* Initialize the TM structure */
  252. X!     midnoon = TMNULL;        /* and our own temp stuff */
  253. X!     btoken.tcnt = btoken.tbrkl = 0;
  254. X!     btoken.tcp = astr;
  255. X  
  256. X! domore:
  257. X!     if(!ptitoken(btoken.tcp+btoken.tcnt,&btoken))    /* Get a token */
  258. X        {     if(btoken.tval.tnum) return(0);         /* Read error? */
  259. X!         if(midnoon != TMNULL)            /* EOF, wrap up */
  260. X!             return(pt12hack(tp, midnoon));
  261. X!         return(1);                /* Win return! */
  262. X        }
  263. X      if(btoken.tflg == 0)        /* Alpha? */
  264. X!       {     twp = btoken.tval.ttmw;         /* Yes, get ptr to entry */
  265. X!         if(twp->wflgs&TWSPEC)        /* Special alpha crock */
  266. X!           {     aproc = (int (*) ()) (twp->wval);
  267. X!             if(!(*aproc)(tp, twp, &btoken))
  268. X!                 return(0);    /* ERR: special word err */
  269. X!             goto domore;
  270. X!           }
  271. X!         if(twp->wflgs&TW1200)
  272. X!             if(ptstash(&midnoon,(int)twp->wval))
  273. X!                 return(0);    /* ERR: noon/midnite clash */
  274. X!             else goto domore;
  275. X!         if(ptstash(&tp[twp->wtype],(int)twp->wval))
  276. X              return(0);        /* ERR: val already set */
  277. X!         if(twp->wtype == TM_ZON)    /* If was zone, hack DST */
  278. X!             if(ptstash(&tp[TM_ISDST],(twp->wflgs&TWDST)))
  279. X!                 return(0);    /* ERR: DST conflict */
  280. X!         goto domore;
  281. X        }
  282. X  
  283. X      /* Token is number.  Lots of hairy heuristics. */
  284. X!     if(btoken.tcnt >= 7)    /* More than 6 digits in string? */
  285. X!         return(0);    /* ERR: number too big */
  286. X!     if(btoken.tcnt == 6)    /* 6 digits = HHMMSS.  Needs special crock */
  287. X!       {            /* since 6 digits are too big for integer! */
  288. X!         i = (btoken.tcp[0]-'0')*10    /* Gobble 1st 2 digits */
  289. X!            + btoken.tcp[1]-'0';
  290. X!         btoken.tcnt = 2;        /* re-read last 4 chars */
  291. X!         goto coltime;
  292. X!       }
  293. X  
  294. X      i = btoken.tval.tnum;   /* Value now known to be valid; get it. */
  295. X!     if( btoken.tcnt == 5    /*  5 digits = HMMSS */
  296. X!      || btoken.tcnt == 3)    /*  3 digits = HMM   */
  297. X!       {    if(btoken.tcnt != 3)
  298. X!             if(ptstash(&tp[TM_SEC], i%100))
  299. X!                 return(0);    /* ERR: sec conflict */
  300. X!             else i /= 100;
  301. X! hhmm4:        if(ptstash(&tp[TM_MIN], i%100))
  302. X              return(0);        /* ERR: min conflict */
  303. X          i /= 100;
  304. X! hh2:            if(ptstash(&tp[TM_HOUR], i))
  305. X              return(0);        /* ERR: hour conflict */
  306. X!         goto domore;
  307. X        }
  308. X  
  309. X      if(btoken.tcnt == 4)    /* 4 digits = YEAR or HHMM */
  310. X!       {    if(tp[TM_YEAR] != TMNULL) goto hhmm4;    /* Already got yr? */
  311. X!         if(tp[TM_HOUR] != TMNULL) goto year4;    /* Already got hr? */
  312. X!         if((i%100) > 59) goto year4;        /* MM >= 60? */
  313. X          if(btoken.tbrk == ':')            /* HHMM:SS ? */
  314. X!             if( ptstash(&tp[TM_HOUR],i/100)
  315. X!              || ptstash(&tp[TM_MIN], i%100))
  316. X                  return(0);        /* ERR: hr/min clash */
  317. X              else goto coltm2;        /* Go handle SS */
  318. X          if(btoken.tbrk != ',' && btoken.tbrk != '/'
  319. X!           && ptitoken(btoken.tcp+btoken.tcnt,&atoken)    /* Peek */
  320. X!           && atoken.tflg == 0            /* alpha */
  321. X!           && (atoken.tval.ttmw->wflgs&TWTIME))  /* HHMM-ZON */
  322. X              goto hhmm4;
  323. X!         if(btoken.tbrkl == '-'        /* DD-Mon-YYYY */
  324. X!           || btoken.tbrkl == ','    /* Mon DD, YYYY */
  325. X!           || btoken.tbrkl == '/'    /* MM/DD/YYYY */
  326. X!           || btoken.tbrkl == '.'    /* DD.MM.YYYY */
  327. X!           || btoken.tbrk == '-'        /* YYYY-MM-DD */
  328. X!             ) goto year4;
  329. X!         goto hhmm4;            /* Give up, assume HHMM. */
  330. X        }
  331. X  
  332. X      /* From this point on, assume tcnt == 1 or 2 */
  333. X!     /* 2 digits = YY, MM, DD, or HH (MM and SS caught at coltime) */
  334. X      if(btoken.tbrk == ':')        /* HH:MM[:SS] */
  335. X          goto coltime;        /*  must be part of time. */
  336. X!     if(i > 31) goto yy2;        /* If >= 32, only YY poss. */
  337. X  
  338. X      /* Check for numerical-format date */
  339. X      for (cp = "/-."; ch = *cp++;)
  340. X--- 231,398 ----
  341. X      char tflg;    /* 0 = alpha, 1 = numeric */
  342. X      union {         /* Resulting value; */
  343. X          int tnum;/* either a #, or */
  344. X!         const struct tmwent *ttmw;/* ptr to a tmwent. */
  345. X      } tval;
  346. X  };
  347. X  
  348. X! static const struct tmwent*ptmatchstr P((const char*,int,const struct tmwent*));
  349. X! static int pt12hack P((struct tm *,int));
  350. X! static int ptitoken P((struct token *));
  351. X! static int ptstash P((int *,int));
  352. X! static int pttoken P((struct token *));
  353. X! 
  354. X!     static int
  355. X! goodzone(t, offset, am)
  356. X!     register const struct token *t;
  357. X!     int offset;
  358. X!     int *am;
  359. X! {
  360. X!     register int m;
  361. X!     if (
  362. X!         t->tflg  &&
  363. X!         t->tcnt == 4+offset  &&
  364. X!         (m = t->tval.tnum) <= 2400  &&
  365. X!         isdigit(t->tcp[offset]) &&
  366. X!         (m%=100) < 60
  367. X!     ) {
  368. X!         m += t->tval.tnum/100 * 60;
  369. X!         if (t->tcp[offset-1]=='+')
  370. X!             m = -m;
  371. X!         *am = m;
  372. X!         return 1;
  373. X!     }
  374. X!     return 0;
  375. X! }
  376. X! 
  377. X!     int
  378. X! partime(astr, atm, zone)
  379. X! const char *astr;
  380. X! register struct tm *atm;
  381. X! int *zone;
  382. X! {
  383. X!     register int i;
  384. X!     struct token btoken, atoken;
  385. X!     int zone_offset; /* minutes west of GMT, plus TZ_OFFSET */
  386. X!     register const char *cp;
  387. X!     register char ch;
  388. X!     int ord, midnoon;
  389. X!     int *atmfield, dst, m;
  390. X!     int got1 = 0;
  391. X! 
  392. X!     atm->tm_sec = TMNULL;
  393. X!     atm->tm_min = TMNULL;
  394. X!     atm->tm_hour = TMNULL;
  395. X!     atm->tm_mday = TMNULL;
  396. X!     atm->tm_mon = TMNULL;
  397. X!     atm->tm_year = TMNULL;
  398. X!     atm->tm_wday = TMNULL;
  399. X!     atm->tm_yday = TMNULL;
  400. X!     midnoon = TMNULL;        /* and our own temp stuff */
  401. X!     zone_offset = TMNULL;
  402. X!     dst = TMNULL;
  403. X!     btoken.tcnt = btoken.tbrk = 0;
  404. X!     btoken.tcp = astr;
  405. X  
  406. X!     for (;; got1=1) {
  407. X!     if (!ptitoken(&btoken))                /* Get a token */
  408. X        {     if(btoken.tval.tnum) return(0);         /* Read error? */
  409. X!         if (given(midnoon))            /* EOF, wrap up */
  410. X!             if (!pt12hack(atm, midnoon))
  411. X!                 return 0;
  412. X!         if (!given(atm->tm_min))
  413. X!             atm->tm_min = 0;
  414. X!         *zone  =
  415. X!                 (given(zone_offset) ? zone_offset-TZ_OFFSET : 0)
  416. X!             -    (given(dst) ? dst : 0);
  417. X!         return got1;
  418. X        }
  419. X      if(btoken.tflg == 0)        /* Alpha? */
  420. X!       {     i = btoken.tval.ttmw->wval;
  421. X!         switch (btoken.tval.ttmw->wtype) {
  422. X!           default:
  423. X!             return 0;
  424. X!           case TM_MON:
  425. X!             atmfield = &atm->tm_mon;
  426. X!             break;
  427. X!           case TM_WDAY:
  428. X!             atmfield = &atm->tm_wday;
  429. X!             break;
  430. X!           case TM_DST:
  431. X!             atmfield = &dst;
  432. X!             break;
  433. X!           case TM_LT:
  434. X!             if (ptstash(&dst, 0))
  435. X!                 return 0;
  436. X!             i = 48*60; /* local time magic number -- see maketime() */
  437. X!             /* fall into */
  438. X!           case TM_ZON:
  439. X!             i += TZ_OFFSET;
  440. X!             if (btoken.tval.ttmw->wflgs & TWDST)
  441. X!                 if (ptstash(&dst, 60))
  442. X!                     return 0;
  443. X!             /* Peek ahead for offset immediately afterwards. */
  444. X!             if (
  445. X!                 (btoken.tbrk=='-' || btoken.tbrk=='+') &&
  446. X!                 (atoken=btoken, ++atoken.tcnt, ptitoken(&atoken)) &&
  447. X!                 goodzone(&atoken, 0, &m)
  448. X!             ) {
  449. X!                 i += m;
  450. X!                 btoken = atoken;
  451. X!             }
  452. X!             atmfield = &zone_offset;
  453. X!             break;
  454. X!           case TM_12:
  455. X!             atmfield = &midnoon;
  456. X!         }
  457. X!         if (ptstash(atmfield, i))
  458. X              return(0);        /* ERR: val already set */
  459. X!         continue;
  460. X        }
  461. X  
  462. X      /* Token is number.  Lots of hairy heuristics. */
  463. X!     if (!isdigit(*btoken.tcp)) {
  464. X!         if (!goodzone(&btoken, 1, &m))
  465. X!             return 0;
  466. X!         zone_offset = TZ_OFFSET + m;
  467. X!         continue;
  468. X!     }
  469. X  
  470. X      i = btoken.tval.tnum;   /* Value now known to be valid; get it. */
  471. X!     if (btoken.tcnt == 3)    /*  3 digits = HMM   */
  472. X!       {
  473. X! hhmm4:        if (ptstash(&atm->tm_min, i%100))
  474. X              return(0);        /* ERR: min conflict */
  475. X          i /= 100;
  476. X! hh2:            if (ptstash(&atm->tm_hour, i))
  477. X              return(0);        /* ERR: hour conflict */
  478. X!         continue;
  479. X        }
  480. X  
  481. X+     if (4 < btoken.tcnt)
  482. X+         goto year4; /* far in the future */
  483. X      if(btoken.tcnt == 4)    /* 4 digits = YEAR or HHMM */
  484. X!       {    if (given(atm->tm_year)) goto hhmm4;    /* Already got yr? */
  485. X!         if (given(atm->tm_hour)) goto year4;    /* Already got hr? */
  486. X          if(btoken.tbrk == ':')            /* HHMM:SS ? */
  487. X!             if ( ptstash(&atm->tm_hour, i/100)
  488. X!               || ptstash(&atm->tm_min, i%100))
  489. X                  return(0);        /* ERR: hr/min clash */
  490. X              else goto coltm2;        /* Go handle SS */
  491. X          if(btoken.tbrk != ',' && btoken.tbrk != '/'
  492. X!           && (atoken=btoken, ptitoken(&atoken))    /* Peek */
  493. X!           && ( atoken.tflg
  494. X!              ? !isdigit(*atoken.tcp)
  495. X!              : atoken.tval.ttmw->wflgs & TWTIME)) /* HHMM-ZON */
  496. X              goto hhmm4;
  497. X!         goto year4;            /* Give up, assume year. */
  498. X        }
  499. X  
  500. X      /* From this point on, assume tcnt == 1 or 2 */
  501. X!     /* 2 digits = MM, DD, or HH (MM and SS caught at coltime) */
  502. X      if(btoken.tbrk == ':')        /* HH:MM[:SS] */
  503. X          goto coltime;        /*  must be part of time. */
  504. X!     if (31 < i)
  505. X!         return 0;
  506. X  
  507. X      /* Check for numerical-format date */
  508. X      for (cp = "/-."; ch = *cp++;)
  509. X***************
  510. X*** 228,416 ****
  511. X        {    ord = (ch == '.' ? 0 : 1);    /* n/m = D/M or M/D */
  512. X          if(btoken.tbrk == ch)            /* "NN-" */
  513. X            {    if(btoken.tbrkl != ch)
  514. X!               {    if(ptitoken(btoken.tcp+btoken.tcnt,&atoken)
  515. X                    && atoken.tflg == 0
  516. X                    && atoken.tval.ttmw->wtype == TM_MON)
  517. X                      goto dd2;
  518. X                  if(ord)goto mm2; else goto dd2; /* "NN-" */
  519. X                }                /* "-NN-" */
  520. X!             if(tp[TM_DAY] == TMNULL
  521. X!             && tp[TM_YEAR] != TMNULL)    /* If "YY-NN-" */
  522. X                  goto mm2;        /* then always MM */
  523. X              if(ord)goto dd2; else goto mm2;
  524. X            }
  525. X          if(btoken.tbrkl == ch            /* "-NN" */
  526. X!           && tp[ord ? TM_MON : TM_DAY] != TMNULL)
  527. X!             if(tp[ord ? TM_DAY : TM_MON] == TMNULL)    /* MM/DD */
  528. X                  if(ord)goto dd2; else goto mm2;
  529. X-             else goto yy2;            /* "-YY" */
  530. X        }
  531. X  
  532. X-     /* At this point only YY, DD, and HH are left.
  533. X-      * YY is very unlikely since value is <= 32 and there was
  534. X-      * no numerical format date.  Make one last try at YY
  535. X-      * before dropping through to DD vs HH code.
  536. X-      */
  537. X-     if(btoken.tcnt == 2        /* If 2 digits */
  538. X-       && tp[TM_HOUR] != TMNULL    /* and already have hour */
  539. X-       && tp[TM_DAY] != TMNULL    /* and day, but  */
  540. X-       && tp[TM_YEAR] == TMNULL)    /* no year, then assume */
  541. X-         goto yy2;        /* that's what we have. */
  542. X- 
  543. X      /* Now reduced to choice between HH and DD */
  544. X!     if(tp[TM_HOUR] != TMNULL) goto dd2;    /* Have hour? Assume day. */
  545. X!     if(tp[TM_DAY] != TMNULL) goto hh2;    /* Have day? Assume hour. */
  546. X      if(i > 24) goto dd2;            /* Impossible HH means DD */
  547. X!     if(!ptitoken(btoken.tcp+btoken.tcnt, &atoken))    /* Read ahead! */
  548. X          if(atoken.tval.tnum) return(0); /* ERR: bad token */
  549. X          else goto dd2;            /* EOF, assume day. */
  550. X!     if( atoken.tflg == 0        /* If next token is an alpha */
  551. X!      && atoken.tval.ttmw->wflgs&TWTIME)  /* time-spec, assume hour */
  552. X          goto hh2;        /* e.g. "3 PM", "11-EDT"  */
  553. X  
  554. X! dd2:    if(ptstash(&tp[TM_DAY],i))    /* Store day (1 based) */
  555. X          return(0);
  556. X!     goto domore;
  557. X  
  558. X! mm2:    if(ptstash(&tp[TM_MON], i-1))    /* Store month (make zero based) */
  559. X          return(0);
  560. X!     goto domore;
  561. X  
  562. X! yy2:    i += 1900;
  563. X! year4:    if(ptstash(&tp[TM_YEAR],i))    /* Store year (full number) */
  564. X          return(0);        /* ERR: year conflict */
  565. X!     goto domore;
  566. X  
  567. X      /* Hack HH:MM[[:]SS] */
  568. X  coltime:
  569. X!     if(ptstash(&tp[TM_HOUR],i)) return(0);
  570. X!     if(!ptitoken(btoken.tcp+btoken.tcnt,&btoken))
  571. X          return(!btoken.tval.tnum);
  572. X      if(!btoken.tflg) return(0);    /* ERR: HH:<alpha> */
  573. X      if(btoken.tcnt == 4)        /* MMSS */
  574. X!         if(ptstash(&tp[TM_MIN],btoken.tval.tnum/100)
  575. X!           || ptstash(&tp[TM_SEC],btoken.tval.tnum%100))
  576. X              return(0);
  577. X!         else goto domore;
  578. X      if(btoken.tcnt != 2
  579. X!       || ptstash(&tp[TM_MIN],btoken.tval.tnum))
  580. X          return(0);        /* ERR: MM bad */
  581. X!     if(btoken.tbrk != ':') goto domore;    /* Seconds follow? */
  582. X! coltm2:    if(!ptitoken(btoken.tcp+btoken.tcnt,&btoken))
  583. X          return(!btoken.tval.tnum);
  584. X      if(!btoken.tflg || btoken.tcnt != 2    /* Verify SS */
  585. X!       || ptstash(&tp[TM_SEC], btoken.tval.tnum))
  586. X          return(0);        /* ERR: SS bad */
  587. X!     goto domore;
  588. X  }
  589. X  
  590. X  /* Store date/time value, return 0 if successful.
  591. X!  * Fails if entry already set to a different value.
  592. X   */
  593. X  ptstash(adr,val)
  594. X  int *adr;
  595. X  {    register int *a;
  596. X!     if( *(a=adr) != TMNULL)
  597. X!         return(*a != val);
  598. X      *a = val;
  599. X      return(0);
  600. X  }
  601. X  
  602. X! /* This subroutine is invoked for NOON or MIDNIGHT when wrapping up
  603. X   * just prior to returning from partime.
  604. X   */
  605. X! pt12hack(atp, aval)
  606. X! int *atp, aval;
  607. X! {    register int *tp, i, h;
  608. X!     tp = atp;
  609. X!     if (((i=tp[TM_MIN]) && i != TMNULL)    /* Ensure mins, secs */
  610. X!      || ((i=tp[TM_SEC]) && i != TMNULL))    /* are 0 or unspec'd */
  611. X!         return(0);            /* ERR: MM:SS not 00:00 */
  612. X!     i = aval;            /* Get 0 or 12 (midnite or noon) */
  613. X!     if ((h = tp[TM_HOUR]) == TMNULL    /* If hour unspec'd, win */
  614. X!      || h == 12)            /* or if 12:00 (matches either) */
  615. X!         tp[TM_HOUR] = i;    /* Then set time */
  616. X!     else if(!(i == 0        /* Nope, but if midnight and */
  617. X!         &&(h == 0 || h == 24)))    /* time matches, can pass. */
  618. X!             return(0);    /* ERR: HH conflicts */
  619. X!     tp[TM_AMPM] = TMNULL;        /* Always reset this value if won */
  620. X!     return(1);
  621. X  }
  622. X  
  623. X- /* Null routine for no-op tokens */
  624. X- 
  625. X- ptnoise() { return(1); }
  626. X- 
  627. X  /* Get a token and identify it to some degree.
  628. X   * Returns 0 on failure; token.tval will be 0 for normal EOF, otherwise
  629. X   * hit error of some sort
  630. X   */
  631. X  
  632. X! ptitoken(astr, tkp)
  633. X  register struct token *tkp;
  634. X- char *astr;
  635. X  {
  636. X!     register char *cp;
  637. X!     register int i;
  638. X  
  639. X!     tkp->tval.tnum = 0;
  640. X!     if(pttoken(astr,tkp) == 0)
  641. X  #ifdef DEBUG
  642. X!     VOID printf("EOF\n");
  643. X! #endif DEBUG
  644. X          return(0);
  645. X      cp = tkp->tcp;
  646. X  
  647. X  #ifdef DEBUG
  648. X!     i = cp[tkp->tcnt];
  649. X!     cp[tkp->tcnt] = 0;
  650. X!     VOID printf("Token: \"%s\" ",cp);
  651. X!     cp[tkp->tcnt] = i;
  652. X! #endif DEBUG
  653. X! 
  654. X!     if(tkp->tflg)
  655. X!         for(i = tkp->tcnt; i > 0; i--)
  656. X!             tkp->tval.tnum = (int)tkp->tval.tnum*10 + ((*cp++)-'0');
  657. X!     else
  658. X!       {     i = ptmatchstr(cp, tkp->tcnt, tmwords);
  659. X!         tkp->tval.tnum = i ? i : -1;         /* Set -1 for error */
  660. X  
  661. X  #ifdef DEBUG
  662. X!         if(!i) VOID printf("Not found!\n");
  663. X! #endif DEBUG
  664. X! 
  665. X!         if(!i) return(0);
  666. X        }
  667. X  
  668. X  #ifdef DEBUG
  669. X      if(tkp->tflg)
  670. X          VOID printf("Val: %d.\n",tkp->tval.tnum);
  671. X!     else VOID printf("Found: \"%s\", val: %d., type %d\n",
  672. X          tkp->tval.ttmw->went,tkp->tval.ttmw->wval,tkp->tval.ttmw->wtype);
  673. X! #endif DEBUG
  674. X  
  675. X      return(1);
  676. X  }
  677. X  
  678. X  /* Read token from input string into token structure */
  679. X! pttoken(astr,tkp)
  680. X  register struct token *tkp;
  681. X- char *astr;
  682. X  {
  683. X!     register char *cp;
  684. X      register int c;
  685. X  
  686. X!     tkp->tcp = cp = astr;
  687. X      tkp->tbrkl = tkp->tbrk;        /* Set "last break" */
  688. X      tkp->tcnt = tkp->tbrk = tkp->tflg = 0;
  689. X  
  690. X      while(c = *cp++)
  691. X        {    switch(c)
  692. X            {    case ' ': case '\t':    /* Flush all whitespace */
  693. X!                 while((c = *cp++) && isspace(c));
  694. X!                 cp--;        /* Drop thru to handle brk */
  695. X              case '(': case ')':    /* Perhaps any non-alphanum */
  696. X              case '-': case ',':    /* shd qualify as break? */
  697. X              case '/': case ':': case '.':    /* Break chars */
  698. X                  if(tkp->tcnt == 0)    /* If no token yet */
  699. X                    {    tkp->tcp = cp;    /* ignore the brk */
  700. X--- 399,606 ----
  701. X        {    ord = (ch == '.' ? 0 : 1);    /* n/m = D/M or M/D */
  702. X          if(btoken.tbrk == ch)            /* "NN-" */
  703. X            {    if(btoken.tbrkl != ch)
  704. X!               {
  705. X!                 atoken = btoken;
  706. X!                 atoken.tcnt++;
  707. X!                 if (ptitoken(&atoken)
  708. X                    && atoken.tflg == 0
  709. X                    && atoken.tval.ttmw->wtype == TM_MON)
  710. X                      goto dd2;
  711. X                  if(ord)goto mm2; else goto dd2; /* "NN-" */
  712. X                }                /* "-NN-" */
  713. X!             if (!given(atm->tm_mday)
  714. X!               && given(atm->tm_year))    /* If "YYYY-NN-" */
  715. X                  goto mm2;        /* then always MM */
  716. X              if(ord)goto dd2; else goto mm2;
  717. X            }
  718. X          if(btoken.tbrkl == ch            /* "-NN" */
  719. X!           && given(ord ? atm->tm_mon : atm->tm_mday))
  720. X!             if (!given(ord ? atm->tm_mday : atm->tm_mon)) /* MM/DD */
  721. X                  if(ord)goto dd2; else goto mm2;
  722. X        }
  723. X  
  724. X      /* Now reduced to choice between HH and DD */
  725. X!     if (given(atm->tm_hour)) goto dd2;    /* Have hour? Assume day. */
  726. X!     if (given(atm->tm_mday)) goto hh2;    /* Have day? Assume hour. */
  727. X!     if (given(atm->tm_mon)) goto dd2;    /* Have month? Assume day. */
  728. X      if(i > 24) goto dd2;            /* Impossible HH means DD */
  729. X!     atoken = btoken;
  730. X!     if (!ptitoken(&atoken))            /* Read ahead! */
  731. X          if(atoken.tval.tnum) return(0); /* ERR: bad token */
  732. X          else goto dd2;            /* EOF, assume day. */
  733. X!     if ( atoken.tflg
  734. X!        ? !isdigit(*atoken.tcp)
  735. X!        : atoken.tval.ttmw->wflgs & TWTIME)
  736. X!         /* If next token is a time spec, assume hour */
  737. X          goto hh2;        /* e.g. "3 PM", "11-EDT"  */
  738. X  
  739. X! dd2:    if (ptstash(&atm->tm_mday, i))    /* Store day (1 based) */
  740. X          return(0);
  741. X!     continue;
  742. X  
  743. X! mm2:    if (ptstash(&atm->tm_mon, i-1))    /* Store month (make zero based) */
  744. X          return(0);
  745. X!     continue;
  746. X  
  747. X! year4:    if ((i-=1900) < 0  ||  ptstash(&atm->tm_year, i)) /* Store year-1900 */
  748. X          return(0);        /* ERR: year conflict */
  749. X!     continue;
  750. X  
  751. X      /* Hack HH:MM[[:]SS] */
  752. X  coltime:
  753. X!     if (ptstash(&atm->tm_hour, i)) return 0;
  754. X!     if (!ptitoken(&btoken))
  755. X          return(!btoken.tval.tnum);
  756. X      if(!btoken.tflg) return(0);    /* ERR: HH:<alpha> */
  757. X      if(btoken.tcnt == 4)        /* MMSS */
  758. X!         if (ptstash(&atm->tm_min, btoken.tval.tnum/100)
  759. X!           || ptstash(&atm->tm_sec, btoken.tval.tnum%100))
  760. X              return(0);
  761. X!         else continue;
  762. X      if(btoken.tcnt != 2
  763. X!       || ptstash(&atm->tm_min, btoken.tval.tnum))
  764. X          return(0);        /* ERR: MM bad */
  765. X!     if (btoken.tbrk != ':') continue;    /* Seconds follow? */
  766. X! coltm2:    if (!ptitoken(&btoken))
  767. X          return(!btoken.tval.tnum);
  768. X      if(!btoken.tflg || btoken.tcnt != 2    /* Verify SS */
  769. X!       || ptstash(&atm->tm_sec, btoken.tval.tnum))
  770. X          return(0);        /* ERR: SS bad */
  771. X!     }
  772. X  }
  773. X  
  774. X  /* Store date/time value, return 0 if successful.
  775. X!  * Fail if entry is already set.
  776. X   */
  777. X+     static int
  778. X  ptstash(adr,val)
  779. X  int *adr;
  780. X+ int val;
  781. X  {    register int *a;
  782. X!     if (given(*(a=adr)))
  783. X!         return 1;
  784. X      *a = val;
  785. X      return(0);
  786. X  }
  787. X  
  788. X! /* This subroutine is invoked for AM, PM, NOON and MIDNIGHT when wrapping up
  789. X   * just prior to returning from partime.
  790. X   */
  791. X!     static int
  792. X! pt12hack(tm, aval)
  793. X! register struct tm *tm;
  794. X! register int aval;
  795. X! {    register int h = tm->tm_hour;
  796. X!     switch (aval) {
  797. X!       case T12_AM:
  798. X!       case T12_PM:
  799. X!         if (h > 12)
  800. X!             return 0;
  801. X!         if (h == 12)
  802. X!             tm->tm_hour = 0;
  803. X!         if (aval == T12_PM)
  804. X!             tm->tm_hour += 12;
  805. X!         break;
  806. X!       default:
  807. X!         if (0 < tm->tm_min  ||  0 < tm->tm_sec)
  808. X!             return 0;
  809. X!         if (!given(h) || h==12)
  810. X!             tm->tm_hour = aval;
  811. X!         else if (aval==T12_MIDNIGHT  &&  (h==0 || h==24))
  812. X!             return 0;
  813. X!     }
  814. X!     return 1;
  815. X  }
  816. X  
  817. X  /* Get a token and identify it to some degree.
  818. X   * Returns 0 on failure; token.tval will be 0 for normal EOF, otherwise
  819. X   * hit error of some sort
  820. X   */
  821. X  
  822. X!     static int
  823. X! ptitoken(tkp)
  824. X  register struct token *tkp;
  825. X  {
  826. X!     register const char *cp;
  827. X!     register int i, j, k;
  828. X  
  829. X!     if (!pttoken(tkp))
  830. X  #ifdef DEBUG
  831. X!         {
  832. X!         VOID printf("EOF\n");
  833. X!         return(0);
  834. X!         }
  835. X! #else
  836. X          return(0);
  837. X+ #endif    
  838. X      cp = tkp->tcp;
  839. X  
  840. X  #ifdef DEBUG
  841. X!     VOID printf("Token: \"%.*s\" ", tkp->tcnt, cp);
  842. X! #endif
  843. X  
  844. X+     if (tkp->tflg) {
  845. X+         i = tkp->tcnt;
  846. X+         if (*cp == '+' || *cp == '-') {
  847. X+             cp++;
  848. X+             i--;
  849. X+         }
  850. X+         while (0 <= --i) {
  851. X+             j = tkp->tval.tnum*10;
  852. X+             k = j + (*cp++ - '0');
  853. X+             if (j/10 != tkp->tval.tnum  ||  k < j) {
  854. X+                 /* arithmetic overflow */
  855. X+                 tkp->tval.tnum = 1;
  856. X+                 return 0;
  857. X+             }
  858. X+             tkp->tval.tnum = k;
  859. X+         }
  860. X+     } else if (!(tkp->tval.ttmw  =  ptmatchstr(cp, tkp->tcnt, tmwords)))
  861. X+       {
  862. X  #ifdef DEBUG
  863. X!         VOID printf("Not found!\n");
  864. X! #endif
  865. X!         tkp->tval.tnum = 1;
  866. X!         return 0;
  867. X        }
  868. X  
  869. X  #ifdef DEBUG
  870. X      if(tkp->tflg)
  871. X          VOID printf("Val: %d.\n",tkp->tval.tnum);
  872. X!     else VOID printf("Found: \"%s\", val: %d, type %d\n",
  873. X          tkp->tval.ttmw->went,tkp->tval.ttmw->wval,tkp->tval.ttmw->wtype);
  874. X! #endif
  875. X  
  876. X      return(1);
  877. X  }
  878. X  
  879. X  /* Read token from input string into token structure */
  880. X!     static int
  881. X! pttoken(tkp)
  882. X  register struct token *tkp;
  883. X  {
  884. X!     register const char *cp;
  885. X      register int c;
  886. X+     const char *astr;
  887. X  
  888. X!     tkp->tcp = astr = cp = tkp->tcp + tkp->tcnt;
  889. X      tkp->tbrkl = tkp->tbrk;        /* Set "last break" */
  890. X      tkp->tcnt = tkp->tbrk = tkp->tflg = 0;
  891. X+     tkp->tval.tnum = 0;
  892. X  
  893. X      while(c = *cp++)
  894. X        {    switch(c)
  895. X            {    case ' ': case '\t':    /* Flush all whitespace */
  896. X!             case '\r': case '\n':
  897. X!             case '\v': case '\f':
  898. X!                 if (!tkp->tcnt) {    /* If no token yet */
  899. X!                     tkp->tcp = cp;    /* ignore the brk */
  900. X!                     continue;    /* and go on. */
  901. X!                 }
  902. X!                 /* fall into */
  903. X              case '(': case ')':    /* Perhaps any non-alphanum */
  904. X              case '-': case ',':    /* shd qualify as break? */
  905. X+             case '+':
  906. X              case '/': case ':': case '.':    /* Break chars */
  907. X                  if(tkp->tcnt == 0)    /* If no token yet */
  908. X                    {    tkp->tcp = cp;    /* ignore the brk */
  909. X***************
  910. X*** 420,476 ****
  911. X                  tkp->tbrk = c;
  912. X                  return(tkp->tcnt);
  913. X            }
  914. X!         if(tkp->tcnt == 0)        /* If first char of token, */
  915. X!             tkp->tflg = isdigit(c);    /*    determine type */
  916. X!           if(( isdigit(c) &&  tkp->tflg)    /* If not first, make sure */
  917. X!          ||(!isdigit(c) && !tkp->tflg))    /*    char matches type */
  918. X!             tkp->tcnt++;        /* Win, add to token. */
  919. X!         else {
  920. X!             cp--;            /* Wrong type, back up */
  921. X              tkp->tbrk = c;
  922. X!             return(tkp->tcnt);
  923. X!           }
  924. X        }
  925. X      return(tkp->tcnt);        /* When hit EOF */
  926. X  }
  927. X  
  928. X  
  929. X  ptmatchstr(astr,cnt,astruc)
  930. X! char *astr;
  931. X! int cnt;
  932. X! struct tmwent *astruc;
  933. X! {    register char *cp, *mp;
  934. X      register int c;
  935. X!     struct tmwent *lastptr;
  936. X!     struct integ { int word; };   /* For getting at array ptr */
  937. X      int i;
  938. X  
  939. X      lastptr = 0;
  940. X!     for(;mp = (char *)((struct integ *)astruc)->word; astruc += 1)
  941. X        {    cp = astr;
  942. X          for(i = cnt; i > 0; i--)
  943. X!           {    switch((c = *cp++) ^ *mp++)    /* XOR the chars */
  944. X                {    case 0: continue;    /* Exact match */
  945. X!                 case 040: if(isalpha(c))
  946. X                      continue;
  947. X                }
  948. X              break;
  949. X            }
  950. X          if(i==0)
  951. X!             if(*mp == 0) return((unsigned int)astruc);    /* Exact match */
  952. X              else if(lastptr) return(0);    /* Ambiguous */
  953. X              else lastptr = astruc;        /* 1st ambig */
  954. X        }
  955. X!     return((unsigned int)lastptr);
  956. X! }
  957. X! 
  958. X! 
  959. X! 
  960. X! zaptime(tp)
  961. X! register int *tp;
  962. X! /* clears tm structure pointed to by tp */
  963. X! {    register int i;
  964. X!     i = (sizeof (struct tm))/(sizeof (int));
  965. X!     do *tp++ = TMNULL;        /* Set entry to "unspecified" */
  966. X!     while(--i);            /* Faster than FOR */
  967. X  }
  968. X--- 610,662 ----
  969. X                  tkp->tbrk = c;
  970. X                  return(tkp->tcnt);
  971. X            }
  972. X!         if (!tkp->tcnt++) {        /* If first char of token, */
  973. X!             if (isdigit(c)) {
  974. X!                 tkp->tflg = 1;
  975. X!                 if (astr<cp-2 && (cp[-2]=='-'||cp[-2]=='+')) {
  976. X!                     /* timezone is break+sign+digit */
  977. X!                     tkp->tcp--;
  978. X!                     tkp->tcnt++;
  979. X!                 }
  980. X!             }
  981. X!         } else if ((isdigit(c)!=0) != tkp->tflg) { /* else check type */
  982. X              tkp->tbrk = c;
  983. X!             return --tkp->tcnt;    /* Wrong type, back up */
  984. X!         }
  985. X        }
  986. X      return(tkp->tcnt);        /* When hit EOF */
  987. X  }
  988. X  
  989. X  
  990. X+     static const struct tmwent *
  991. X  ptmatchstr(astr,cnt,astruc)
  992. X!     const char *astr;
  993. X!     int cnt;
  994. X!     const struct tmwent *astruc;
  995. X! {
  996. X!     register const char *cp, *mp;
  997. X      register int c;
  998. X!     const struct tmwent *lastptr;
  999. X      int i;
  1000. X  
  1001. X      lastptr = 0;
  1002. X!     for(;mp = astruc->went; astruc += 1)
  1003. X        {    cp = astr;
  1004. X          for(i = cnt; i > 0; i--)
  1005. X!           {
  1006. X!             switch (*cp++ - (c = *mp++))
  1007. X                {    case 0: continue;    /* Exact match */
  1008. X!                 case 'A'-'a':
  1009. X!                     /* `if (ctab[c]==Letter)' in RCS */
  1010. X!                     if (islower(c))
  1011. X                      continue;
  1012. X                }
  1013. X              break;
  1014. X            }
  1015. X          if(i==0)
  1016. X!             if (!*mp) return astruc;    /* Exact match */
  1017. X              else if(lastptr) return(0);    /* Ambiguous */
  1018. X              else lastptr = astruc;        /* 1st ambig */
  1019. X        }
  1020. X!     return lastptr;
  1021. X  }
  1022. Xdiff -c src/patch.c:1.6 src/patch.c:1.6.1.1
  1023. X*** src/patch.c:1.6    Wed Feb  6 11:32:13 1991
  1024. X--- src/patch.c    Wed Feb  6 11:32:14 1991
  1025. X***************
  1026. X*** 1,5 ****
  1027. X  #ifndef lint
  1028. X! static char rcsid[] = "$Id: patch.c,v 1.6 90/02/14 10:01:33 berliner Exp $";
  1029. X  #endif !lint
  1030. X  
  1031. X  /*
  1032. X--- 1,5 ----
  1033. X  #ifndef lint
  1034. X! static char rcsid[] = "$Id: patch.c,v 1.6.1.1 91/01/18 12:18:45 berliner Exp $";
  1035. X  #endif !lint
  1036. X  
  1037. X  /*
  1038. X***************
  1039. X*** 22,29 ****
  1040. X  #include <ctype.h>
  1041. X  #include "cvs.h"
  1042. X  
  1043. X- extern long maketime();
  1044. X- 
  1045. X  extern char update_dir[];
  1046. X  extern DBM *open_module();
  1047. X  extern int force_tag_match;
  1048. X--- 22,27 ----
  1049. X***************
  1050. X*** 106,112 ****
  1051. X      error(0, "must specify at least one revision/date!");
  1052. X      }
  1053. X      if (date1[0] != '\0' && date2[0] != '\0') {
  1054. X!     if (strcmp(date1, date2) >= 0)
  1055. X          error(0, "second date must come after first date!");
  1056. X      }
  1057. X      (void) signal(SIGHUP, patch_cleanup);
  1058. X--- 104,110 ----
  1059. X      error(0, "must specify at least one revision/date!");
  1060. X      }
  1061. X      if (date1[0] != '\0' && date2[0] != '\0') {
  1062. X!     if (datecmp(date1, date2) >= 0)
  1063. X          error(0, "second date must come after first date!");
  1064. X      }
  1065. X      (void) signal(SIGHUP, patch_cleanup);
  1066. X***************
  1067. X*** 379,395 ****
  1068. X          if (*cp && (semi = index(cp, ';')) != NULL) {
  1069. X          ret = 0;
  1070. X          *semi = '\0';
  1071. X!         ftm = &tm;
  1072. X!         zaptime((int *)ftm);
  1073. X!         (void) sscanf(cp, DATEFORM, &ftm->tm_year, &ftm->tm_mon,
  1074. X!                   &ftm->tm_mday, &ftm->tm_hour, &ftm->tm_min,
  1075. X!                   &ftm->tm_sec);
  1076. X!         ftm->tm_mon--;
  1077. X!         revdate = (time_t)maketime(ftm) - 1;
  1078. X!         ftm = localtime(&revdate);
  1079. X!         (void) sprintf(date, DATEFORM, ftm->tm_year, ftm->tm_mon+1,
  1080. X!                    ftm->tm_mday, ftm->tm_hour, ftm->tm_min,
  1081. X!                    ftm->tm_sec);
  1082. X          }
  1083. X          break;
  1084. X      }
  1085. X--- 377,383 ----
  1086. X          if (*cp && (semi = index(cp, ';')) != NULL) {
  1087. X          ret = 0;
  1088. X          *semi = '\0';
  1089. X!         semi[-1]--;    /* This works even if semi[-1] was '0'.  */
  1090. X          }
  1091. X          break;
  1092. X      }
  1093. Xdiff -c src/patchlevel.h:1.1 src/patchlevel.h:1.1.1.1
  1094. X*** src/patchlevel.h:1.1    Wed Feb  6 11:32:12 1991
  1095. X--- src/patchlevel.h    Wed Feb  6 11:32:12 1991
  1096. X***************
  1097. X*** 1,3 ****
  1098. X! /*    $Id: patchlevel.h,v 1.1 89/11/20 00:06:30 berliner Exp $    */
  1099. X  
  1100. X! #define    PATCHLEVEL    0
  1101. X--- 1,3 ----
  1102. X! /*    $Id: patchlevel.h,v 1.1.1.1 91/01/18 12:19:46 berliner Exp $    */
  1103. X  
  1104. X! #define    PATCHLEVEL    2
  1105. Xdiff -c src/rcstime.h:1.1 src/rcstime.h:removed
  1106. X*** src/rcstime.h:1.1    Wed Feb  6 11:32:08 1991
  1107. X--- src/rcstime.h    Wed Feb  6 11:32:08 1991
  1108. X***************
  1109. X*** 1,42 ****
  1110. X- #define TIMEID "$Id: rcstime.h,v 1.1 89/05/09 11:51:03 berliner Exp $"
  1111. X- 
  1112. X- /* Structure for use by time manipulating subroutines.
  1113. X-  * The following library routines use it:
  1114. X-  *    libc: ctime, localtime, gmtime, asctime
  1115. X-  *    libcx: partime, maketime (may not be installed yet)
  1116. X-  */
  1117. X- 
  1118. X- struct tm {     /* See defines below for allowable ranges */
  1119. X-     int tm_sec;
  1120. X-     int tm_min;
  1121. X-     int tm_hour;
  1122. X-     int tm_mday;
  1123. X-     int tm_mon;
  1124. X-     int tm_year;
  1125. X-     int tm_wday;
  1126. X-     int tm_yday;
  1127. X-     int tm_isdst;
  1128. X-     int tm_zon;    /* NEW: mins westward of Greenwich */
  1129. X-     int tm_ampm;    /* NEW: 1 if AM, 2 if PM */
  1130. X- };
  1131. X- 
  1132. X- #define LCLZONE (5*60)    /* Until V7 ftime(2) works, this defines local zone*/
  1133. X- #define TMNULL (-1)    /* Items not specified are given this value
  1134. X-              * in order to distinguish null specs from zero
  1135. X-              * specs.  This is only used by partime and
  1136. X-              * maketime. */
  1137. X- 
  1138. X-     /* Indices into TM structure */
  1139. X- #define TM_SEC 0    /* 0-59            */
  1140. X- #define TM_MIN 1    /* 0-59            */
  1141. X- #define TM_HOUR 2    /* 0-23            */
  1142. X- #define TM_MDAY 3    /* 1-31            day of month */
  1143. X- #define TM_DAY TM_MDAY    /*  "            synonym      */
  1144. X- #define TM_MON 4    /* 0-11            */
  1145. X- #define TM_YEAR 5    /* (year-1900) (year)    */
  1146. X- #define TM_WDAY 6    /* 0-6            day of week (0 = Sunday) */
  1147. X- #define TM_YDAY 7    /* 0-365        day of year */
  1148. X- #define TM_ISDST 8    /* 0 Std, 1 DST        */
  1149. X-     /* New stuff */
  1150. X- #define TM_ZON 9    /* 0-(24*60) minutes west of Greenwich */
  1151. X- #define TM_AMPM 10    /* 1 AM, 2 PM        */
  1152. X--- 0 ----
  1153. Xdiff -c src/subr.c:1.14 src/subr.c:1.14.1.2
  1154. X*** src/subr.c:1.14    Wed Feb  6 11:32:11 1991
  1155. X--- src/subr.c    Wed Feb  6 11:32:11 1991
  1156. X***************
  1157. X*** 1,5 ****
  1158. X  #ifndef lint
  1159. X! static char rcsid[] = "$Id: subr.c,v 1.14 89/11/20 09:51:10 berliner Exp $";
  1160. X  #endif !lint
  1161. X  
  1162. X  /*
  1163. X--- 1,5 ----
  1164. X  #ifndef lint
  1165. X! static char rcsid[] = "$Id: subr.c,v 1.14.1.2 91/01/29 19:46:20 berliner Exp $";
  1166. X  #endif !lint
  1167. X  
  1168. X  /*
  1169. X***************
  1170. X*** 114,120 ****
  1171. X  
  1172. X      if (stat(file, &sb) < 0)
  1173. X      return (0);
  1174. X!     return ((sb.st_mode & S_IFMT) & S_IFDIR);
  1175. X  }
  1176. X  
  1177. X  /*
  1178. X--- 114,120 ----
  1179. X  
  1180. X      if (stat(file, &sb) < 0)
  1181. X      return (0);
  1182. X!     return ((sb.st_mode & S_IFMT) == S_IFDIR);
  1183. X  }
  1184. X  
  1185. X  /*
  1186. X***************
  1187. X*** 125,133 ****
  1188. X  {
  1189. X      struct stat sb;
  1190. X  
  1191. X      if (lstat(file, &sb) < 0)
  1192. X      return (0);
  1193. X!     return ((sb.st_mode & S_IFMT) & S_IFLNK);
  1194. X  }
  1195. X  
  1196. X  /*
  1197. X--- 125,137 ----
  1198. X  {
  1199. X      struct stat sb;
  1200. X  
  1201. X+ #ifdef S_IFLNK
  1202. X      if (lstat(file, &sb) < 0)
  1203. X      return (0);
  1204. X!     return ((sb.st_mode & S_IFMT) == S_IFLNK);
  1205. X! #else
  1206. X!     return (0);
  1207. X! #endif
  1208. X  }
  1209. X  
  1210. X  /*
  1211. Xdiff -c src/tag.c:1.19 src/tag.c:1.19.1.2
  1212. X*** src/tag.c:1.19    Wed Feb  6 11:32:10 1991
  1213. X--- src/tag.c    Wed Feb  6 11:32:10 1991
  1214. X***************
  1215. X*** 1,5 ****
  1216. X  #ifndef lint
  1217. X! static char rcsid[] = "$Id: tag.c,v 1.19 89/11/19 23:40:46 berliner Exp $";
  1218. X  #endif !lint
  1219. X  
  1220. X  /*
  1221. X--- 1,5 ----
  1222. X  #ifndef lint
  1223. X! static char rcsid[] = "$Id: tag.c,v 1.19.1.2 91/01/29 19:45:54 berliner Exp $";
  1224. X  #endif !lint
  1225. X  
  1226. X  /*
  1227. X***************
  1228. X*** 180,185 ****
  1229. X--- 180,205 ----
  1230. X  {
  1231. X      char version[50];
  1232. X  
  1233. X+ #ifdef S_IFLNK
  1234. X+     /*
  1235. X+      * Ooops..  if there is a symbolic link in the source repository
  1236. X+      * which points to a normal file, rcs will do its file renaming
  1237. X+      * mumbo-jumbo and blow away the symbolic link; this is essentially
  1238. X+      * like a copy-on-commit RCS revision control file, but I consider
  1239. X+      * it a bug.  Instead, read the contents of the link and recursively
  1240. X+      * tag the link contents (which may be a symlink itself...).
  1241. X+      */
  1242. X+     if (islink(rcs) && isfile(rcs)) {
  1243. X+     char link_name[MAXPATHLEN];
  1244. X+     int count;
  1245. X+ 
  1246. X+     if ((count = readlink(rcs, link_name, sizeof(link_name))) != -1) {
  1247. X+         link_name[count] = '\0';
  1248. X+         return (tag_file(link_name));
  1249. X+     }
  1250. X+     }
  1251. X+ #endif
  1252. X+ 
  1253. X      if (delete) {
  1254. X      /*
  1255. X       * If -d is specified, "force_tag_match" is set, so that this call
  1256. X***************
  1257. X*** 210,220 ****
  1258. X      }
  1259. X      Version_Number(rcs, numtag, Date, version);
  1260. X      if (version[0] == '\0') {
  1261. X!     if (!really_quiet) {
  1262. X          warn(0, "cannot find tag '%s' for %s", numtag[0] ? numtag : "head",
  1263. X           rcs);
  1264. X      }
  1265. X!     return (1);
  1266. X      }
  1267. X      if (isdigit(numtag[0]) && strcmp(numtag, version) != 0) {
  1268. X      /*
  1269. X--- 230,241 ----
  1270. X      }
  1271. X      Version_Number(rcs, numtag, Date, version);
  1272. X      if (version[0] == '\0') {
  1273. X!     if (!quiet) {
  1274. X          warn(0, "cannot find tag '%s' for %s", numtag[0] ? numtag : "head",
  1275. X           rcs);
  1276. X+         return (1);
  1277. X      }
  1278. X!     return (0);
  1279. X      }
  1280. X      if (isdigit(numtag[0]) && strcmp(numtag, version) != 0) {
  1281. X      /*
  1282. Xdiff -c src/update.c:1.27 src/update.c:1.27.1.2
  1283. X*** src/update.c:1.27    Wed Feb  6 11:32:16 1991
  1284. X--- src/update.c    Wed Feb  6 11:32:16 1991
  1285. X***************
  1286. X*** 1,5 ****
  1287. X  #ifndef lint
  1288. X! static char rcsid[] = "$Id: update.c,v 1.27 89/11/19 23:40:48 berliner Exp $";
  1289. X  #endif !lint
  1290. X  
  1291. X  /*
  1292. X--- 1,5 ----
  1293. X  #ifndef lint
  1294. X! static char rcsid[] = "$Id: update.c,v 1.27.1.2 91/02/06 18:30:07 berliner Exp $";
  1295. X  #endif !lint
  1296. X  
  1297. X  /*
  1298. X***************
  1299. X*** 111,117 ****
  1300. X      if (!isdir(CVSADM)) {
  1301. X      if (!quiet)
  1302. X          warn(0, "warning: no %s directory found", CVSADM);
  1303. X!     err += update_descend(update_recursive);
  1304. X      return (err);
  1305. X      }
  1306. X      Name_Repository();
  1307. X--- 111,132 ----
  1308. X      if (!isdir(CVSADM)) {
  1309. X      if (!quiet)
  1310. X          warn(0, "warning: no %s directory found", CVSADM);
  1311. X!     if (argc <= 0) {
  1312. X!         err += update_descend(update_recursive);
  1313. X!     } else {
  1314. X!         int i;
  1315. X! 
  1316. X!         for (i = 0; i < argc; i++) {
  1317. X!         if (isdir(argv[i])) {
  1318. X!             (void) strcat(Dlist, " ");
  1319. X!             (void) strcat(Dlist, argv[i]);
  1320. X!         } else {
  1321. X!             warn(0, "nothing known about %s", argv[i]);
  1322. X!             err++;
  1323. X!         }
  1324. X!         }
  1325. X!         err += update_process_lists();
  1326. X!     }
  1327. X      return (err);
  1328. X      }
  1329. X      Name_Repository();
  1330. X***************
  1331. X*** 175,180 ****
  1332. X--- 190,196 ----
  1333. X      update_Files = 1;
  1334. X      (void) strcpy(User, cp);
  1335. X      Scratch_Entry(User);
  1336. X+     (void) unlink(User);
  1337. X      }
  1338. X      /*
  1339. X       * Olist is the "needs checking out" list.
  1340. X***************
  1341. X*** 349,359 ****
  1342. X          strcmp(dp->d_name, CVSLCK) == 0)
  1343. X          continue;
  1344. X          (void) sprintf(fname, "%s/%s", Repository, dp->d_name);
  1345. X          if (!isdir(fname))
  1346. X          continue;
  1347. X!         if (isdir(dp->d_name))
  1348. X          continue;
  1349. X!         if (isfile(dp->d_name)) {
  1350. X          warn(0, "file %s should be a directory; please move it", dp->d_name);
  1351. X          err++;
  1352. X          } else {
  1353. X--- 365,376 ----
  1354. X          strcmp(dp->d_name, CVSLCK) == 0)
  1355. X          continue;
  1356. X          (void) sprintf(fname, "%s/%s", Repository, dp->d_name);
  1357. X+         (void) sprintf(tmp, "%s/%s", dp->d_name, CVSADM);
  1358. X          if (!isdir(fname))
  1359. X          continue;
  1360. X!         if (islink(dp->d_name) || isdir(tmp))
  1361. X          continue;
  1362. X!         if (!isdir(dp->d_name) && isfile(dp->d_name)) {
  1363. X          warn(0, "file %s should be a directory; please move it", dp->d_name);
  1364. X          err++;
  1365. X          } else {
  1366. Xdiff -c src/version_number.c:1.16 src/version_number.c:1.16.1.2
  1367. X*** src/version_number.c:1.16    Wed Feb  6 11:32:09 1991
  1368. X--- src/version_number.c    Wed Feb  6 11:32:09 1991
  1369. X***************
  1370. X*** 1,5 ****
  1371. X  #ifndef lint
  1372. X! static char rcsid[] = "$Id: version_number.c,v 1.16 89/11/19 23:20:35 berliner Exp $";
  1373. X  #endif !lint
  1374. X  
  1375. X  /*
  1376. X--- 1,5 ----
  1377. X  #ifndef lint
  1378. X! static char rcsid[] = "$Id: version_number.c,v 1.16.1.2 91/01/29 07:20:26 berliner Exp $";
  1379. X  #endif !lint
  1380. X  
  1381. X  /*
  1382. X***************
  1383. X*** 67,72 ****
  1384. X--- 67,73 ----
  1385. X          (void) strcpy(vers, rev);
  1386. X          }
  1387. X      } else {
  1388. X+         if (!force_tag_match)
  1389. X          (void) strcpy(vers, rev);
  1390. X      }
  1391. X      }
  1392. X***************
  1393. X*** 100,105 ****
  1394. X--- 101,107 ----
  1395. X      if (fgets(line, sizeof(line), fp) == NULL)
  1396. X      return;
  1397. X      if (strncmp(line, RCSHEAD, sizeof(RCSHEAD) - 1) != 0 ||
  1398. X+     !isspace(line[sizeof(RCSHEAD) - 1]) ||
  1399. X      (cp = rindex(line, ';')) == NULL)
  1400. X      return;
  1401. X      *cp = '\0';                /* strip the ';' */
  1402. X***************
  1403. X*** 119,124 ****
  1404. X--- 121,127 ----
  1405. X      if (fgets(line, sizeof(line), fp) == NULL)
  1406. X      return;
  1407. X      if (strncmp(line, RCSBRANCH, sizeof(RCSBRANCH) - 1) == 0 &&
  1408. X+     isspace(line[sizeof(RCSBRANCH) - 1]) &&
  1409. X      (cp = rindex(line, ';')) != NULL) {
  1410. X      *cp = '\0';            /* strip the ';' */
  1411. X      if ((cp = rindex(line, ' ')) == NULL &&
  1412. X***************
  1413. X*** 149,156 ****
  1414. X       * the highest numbered branch off "rev", if necessary.
  1415. X       */
  1416. X      get_branch(fp, rev);
  1417. X!     if (tag[0] == '\0' || isdigit(tag[0]) || symtag_matched < 0)
  1418. X!     (void) strcpy(vers, rev);
  1419. X  }
  1420. X  
  1421. X  /*
  1422. X--- 152,161 ----
  1423. X       * the highest numbered branch off "rev", if necessary.
  1424. X       */
  1425. X      get_branch(fp, rev);
  1426. X!     if (tag[0] == '\0' || isdigit(tag[0]) || symtag_matched < 0) {
  1427. X!     if ((numdots(rev) & 1) != 0)
  1428. X!         (void) strcpy(vers, rev);
  1429. X!     }
  1430. X  }
  1431. X  
  1432. X  /*
  1433. X***************
  1434. X*** 172,196 ****
  1435. X      char *rev;
  1436. X      char *vers;
  1437. X  {
  1438. X!     char line[MAXLINELEN], tagdot[50];
  1439. X      char *cp, *cprev;
  1440. X-     int tagdots, tagdotlen;
  1441. X  
  1442. X      if (isdigit(tag[0])) {
  1443. X!     while (tag[strlen(tag)] == '.')
  1444. X!         tag[strlen(tag)] = '\0';    /* strip trailing dots */
  1445. X!     (void) sprintf(tagdot, "%s.", tag);
  1446. X!     tagdotlen = strlen(tagdot);
  1447. X!     tagdots = numdots(tag);
  1448. X      }
  1449. X      while (fgets(line, sizeof(line), fp) != NULL) {
  1450. X      if (strncmp(line, RCSDESC, sizeof(RCSDESC) - 1) == 0) {
  1451. X-         /*
  1452. X-          * Use head, or a partial branch match found with the strncmp
  1453. X-          * call with tagdot below
  1454. X-          */
  1455. X          rewind(fp);
  1456. X!         return (1);
  1457. X      }
  1458. X      /*
  1459. X       * For numeric tags, the RCS file contains the revision
  1460. X--- 177,197 ----
  1461. X      char *rev;
  1462. X      char *vers;
  1463. X  {
  1464. X!     char line[MAXLINELEN];
  1465. X      char *cp, *cprev;
  1466. X  
  1467. X      if (isdigit(tag[0])) {
  1468. X!     while (tag[strlen(tag)-1] == '.')
  1469. X!         tag[strlen(tag)-1] = '\0';    /* strip trailing dots */
  1470. X!     if ((numdots(tag) & 1) == 0) {
  1471. X!         (void) strcpy(rev, tag);
  1472. X!         return (1);            /* let get_branch() figure it out */
  1473. X!     }
  1474. X      }
  1475. X      while (fgets(line, sizeof(line), fp) != NULL) {
  1476. X      if (strncmp(line, RCSDESC, sizeof(RCSDESC) - 1) == 0) {
  1477. X          rewind(fp);
  1478. X!         return (1);            /* use head */
  1479. X      }
  1480. X      /*
  1481. X       * For numeric tags, the RCS file contains the revision
  1482. X***************
  1483. X*** 204,221 ****
  1484. X          (void) strcpy(vers, line);
  1485. X          return (0);        /* a match for a numeric tag */
  1486. X          }
  1487. X-         if (strncmp(tagdot, line, tagdotlen) == 0) {
  1488. X-         if ((tagdots & 1) == 0 && numdots(line) == tagdots+1)
  1489. X-             (void) strcpy(rev, line);
  1490. X-         }
  1491. X          continue;
  1492. X      }
  1493. X      if (strncmp(line, RCSSYMBOL, sizeof(RCSSYMBOL)-1)!=0 ||
  1494. X!         (cp = rindex(line, ';')) == NULL)
  1495. X!         continue;
  1496. X!     *cp = ' ';            /* strip the ';' */
  1497. X!     if ((cp = index(line, ' ')) == NULL &&
  1498. X!         (cp = index(line, '\t')) == NULL)
  1499. X          continue;
  1500. X      /*
  1501. X       * A rather ugly loop to process the "symbols" line.  I would
  1502. X--- 205,214 ----
  1503. X          (void) strcpy(vers, line);
  1504. X          return (0);        /* a match for a numeric tag */
  1505. X          }
  1506. X          continue;
  1507. X      }
  1508. X      if (strncmp(line, RCSSYMBOL, sizeof(RCSSYMBOL)-1)!=0 ||
  1509. X!         !isspace(line[sizeof(RCSSYMBOL) - 1]))
  1510. X          continue;
  1511. X      /*
  1512. X       * A rather ugly loop to process the "symbols" line.  I would
  1513. X***************
  1514. X*** 222,233 ****
  1515. X       * really rather use strtok(), but other above me already are,
  1516. X       * and strtok() blows up in this case.
  1517. X       */
  1518. X!     while (cp && *cp) {
  1519. X          while (isspace(*cp))
  1520. X          cp++;
  1521. X          /* symbols and revisions are separated by a colon */
  1522. X          if ((cprev = index(cp, ':')) == NULL) {
  1523. X!         while (*cp && !isspace(*cp))
  1524. X              cp++;
  1525. X          continue;
  1526. X          }
  1527. X--- 215,234 ----
  1528. X       * really rather use strtok(), but other above me already are,
  1529. X       * and strtok() blows up in this case.
  1530. X       */
  1531. X!     for (cp = line + sizeof(RCSSYMBOL);  cp;  ) {
  1532. X          while (isspace(*cp))
  1533. X          cp++;
  1534. X+         if (*cp == ';')
  1535. X+         break;
  1536. X+         if (!*cp) {
  1537. X+             if (fgets(line, sizeof(line), fp) == NULL)
  1538. X+             return 0;
  1539. X+         cp = line;
  1540. X+         continue;
  1541. X+         }
  1542. X          /* symbols and revisions are separated by a colon */
  1543. X          if ((cprev = index(cp, ':')) == NULL) {
  1544. X!         while (*cp && !isspace(*cp) && *cp!=';')
  1545. X              cp++;
  1546. X          continue;
  1547. X          }
  1548. X***************
  1549. X*** 245,253 ****
  1550. X          (void) strcpy(rev, cprev);
  1551. X          return (-1);        /* look for branches off rev */
  1552. X          } else {
  1553. X!         while (!isspace(*cp))
  1554. X              cp++;
  1555. X-         cp++;
  1556. X          }
  1557. X      }
  1558. X      return (1);
  1559. X--- 246,253 ----
  1560. X          (void) strcpy(rev, cprev);
  1561. X          return (-1);        /* look for branches off rev */
  1562. X          } else {
  1563. X!         while (!isspace(*cp) && *cp!=';')
  1564. X              cp++;
  1565. X          }
  1566. X      }
  1567. X      return (1);
  1568. X***************
  1569. X*** 282,288 ****
  1570. X          *cp = '\0';        /* strip the newline */
  1571. X          if (numdots(line) == dots+1 &&
  1572. X          strncmp(line, branch, len) == 0) {
  1573. X!         if (strcmp(branch, line) <= 0)
  1574. X              (void) strcpy(rev, line);
  1575. X          }
  1576. X      }
  1577. X--- 282,288 ----
  1578. X          *cp = '\0';        /* strip the newline */
  1579. X          if (numdots(line) == dots+1 &&
  1580. X          strncmp(line, branch, len) == 0) {
  1581. X!         if ((numdots(rev) & 1) == 0 || strcmp(rev, line) <= 0)
  1582. X              (void) strcpy(rev, line);
  1583. X          }
  1584. X      }
  1585. X***************
  1586. X*** 342,348 ****
  1587. X      char *cp, *semi;
  1588. X  
  1589. X      last_rev[0] = '\0';
  1590. X!     (void) strcpy(curdate, "00");    /* what happens at 2000 ad? */
  1591. X      (void) sprintf(date_dot, "%s.", rev);
  1592. X      date_dotlen = strlen(date_dot);
  1593. X      date_dots = numdots(rev);
  1594. X--- 342,348 ----
  1595. X      char *cp, *semi;
  1596. X  
  1597. X      last_rev[0] = '\0';
  1598. X!     curdate[0] = '\0';
  1599. X      (void) sprintf(date_dot, "%s.", rev);
  1600. X      date_dotlen = strlen(date_dot);
  1601. X      date_dots = numdots(rev);
  1602. X***************
  1603. X*** 360,365 ****
  1604. X--- 360,366 ----
  1605. X          continue;
  1606. X      }
  1607. X      if (strncmp(line, RCSDATE, sizeof(RCSDATE) - 1) == 0 &&
  1608. X+         isspace(line[sizeof(RCSDATE) - 1]) &&
  1609. X          last_rev[0] != '\0') {
  1610. X          for (cp = line; *cp && !isspace(*cp); cp++)
  1611. X          ;
  1612. X***************
  1613. X*** 367,373 ****
  1614. X          cp++;
  1615. X          if (*cp && (semi = index(cp, ';')) != NULL) {
  1616. X          *semi = '\0';        /* strip the semicolon */
  1617. X!         if (strcmp(cp, date) <= 0 && strcmp(cp, curdate) >= 0) {
  1618. X              (void) strcpy(curdate, cp);
  1619. X              (void) strcpy(version, last_rev);
  1620. X          }
  1621. X--- 368,374 ----
  1622. X          cp++;
  1623. X          if (*cp && (semi = index(cp, ';')) != NULL) {
  1624. X          *semi = '\0';        /* strip the semicolon */
  1625. X!         if (datecmp(cp, date) <= 0 && datecmp(cp, curdate) >= 0) {
  1626. X              (void) strcpy(curdate, cp);
  1627. X              (void) strcpy(version, last_rev);
  1628. X          }
  1629. X***************
  1630. X*** 374,377 ****
  1631. X--- 375,391 ----
  1632. X          }
  1633. X      }
  1634. X      }
  1635. X+ }
  1636. X+ 
  1637. X+ /*
  1638. X+  * Compare two dates in RCS format.
  1639. X+  * Beware the change in format on January 1, 2000,
  1640. X+  * when years go from 2-digit to full format.
  1641. X+  */
  1642. X+ int
  1643. X+ datecmp(date1, date2)
  1644. X+     char *date1, *date2;
  1645. X+ {
  1646. X+     int length_diff = strlen(date1) - strlen(date2);
  1647. X+     return length_diff ? length_diff : strcmp(date1, date2);
  1648. X  }
  1649. X
  1650. END_OF_FILE
  1651.   if test 48942 -ne `wc -c <'Patch02.02'`; then
  1652.     echo shar: \"'Patch02.02'\" unpacked with wrong size!
  1653.   fi
  1654.   # end of 'Patch02.02'
  1655. fi
  1656. echo shar: End of archive 2 \(of 2\).
  1657. cp /dev/null ark2isdone
  1658. MISSING=""
  1659. for I in 1 2 ; do
  1660.     if test ! -f ark${I}isdone ; then
  1661.     MISSING="${MISSING} ${I}"
  1662.     fi
  1663. done
  1664. if test "${MISSING}" = "" ; then
  1665.     echo You have unpacked both archives.
  1666.     rm -f ark[1-9]isdone
  1667. else
  1668.     echo You still must unpack the following archives:
  1669.     echo "        " ${MISSING}
  1670. fi
  1671. exit 0
  1672. exit 0 # Just in case...
  1673.